﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace LevSTProgramTransform
{
    class ReceiveDataTransform
    {
        const string Define_OneWire_SystemData_Str = "OneWire_SystemData_Group";
        const string Define_OneWire_EEPROM_Str = "OneWire_EEPROM_Group";
        string OneWire_SystemData_Str = "";
        string OneWire_EEPROM_Str = "";
        public byte[] OneWire_SystemData;
        public byte[] OneWire_EEPROM;

        public const int Cal_Offset = 0x10; 
        public const int Cal_Length = 6; 
        byte[] Cal_Data = new byte[Cal_Length];

        public const int MaSN_Offset = 0x6A; 
        public const int MaSN_Length = 4; 
        public byte[] MaSN_Data = new byte[MaSN_Length];

        public const int BarCode1_Offset = 0x10C; 
        public const int BarCode1_Length = 20; 
        public byte[] BarCode1_Data = new byte[BarCode1_Length];

        public const int BarCode2_Offset = 0x120; 
        public const int BarCode2_Length = 4; 
        public byte[] BarCode2_Data = new byte[BarCode2_Length];
        /// <summary>
        /// /////////////////////////////////////////////////////
        /// </summary>
        const string HexTransformPath = @".\TransformHex"; 
        const string HexTemplatePath = @".\TemplateFiles";
        //const string HexTemplatePRGFile = "Pan_RN1_48087_NU_13S3P4LEDLowDrv_SDI29E_SW1_Aslp_Wup_CC_DUVP_136R_V3.6.25.1.hex";
        //const string HexTemplateROMFile = "_UserDefine_Pan_RN1_48087_NU_13S3P4LEDLowDrv_SDI29E_SW1_Aslp_Wup_CC_DUVP_136R_V25.hex";
        string HexDirectoryName;
        string HexTemplatePRGFile;
        string HexTemplateROMFile;
        const string HexTemplateLockFile = "STM8L151K6_OPT_Lock.hex";
        const string HexTemplateUnlockFile = "STM8L151K6_OPT_Unlock.hex";
        //const string ProgrammingPath = @"C:\Program Files\STMicroelectronics\st_toolset\stvp";
        const string ProgrammingPath = @".\Stvp_GV";
        const string ProgrammingFile = "STVP_CmdLine.exe";
        const string ProgrammingArgumentsPRG = @"-BoardName=ST-LINK -Port=USB -ProgMode=SWIM -Device=STM8L15xK6 -no_Loop -verif -FileProg=";
        const string ProgrammingArgumentsROM = @"-BoardName=ST-LINK -Port=USB -ProgMode=SWIM -Device=STM8L15xK6 -no_Loop -verif -FileData=";
        const string ProgrammingArgumentsLOCK = @"-BoardName=ST-LINK -Port=USB -ProgMode=SWIM -Device=STM8L15xK6 -no_Loop -verif -no_warn_protect -FileOption=";
        const string ProgrammingArgumentsUNLOCK = @"-BoardName=ST-LINK -Port=USB -ProgMode=SWIM -Device=STM8L15xK6 -no_Loop -verif -no_warn_protect -FileOption=";

        public string TransforHexFile;
        public string BarCodeID;

        public ReceiveDataTransform(string prghex, string romhex)
        {
            HexTemplatePRGFile = prghex;
            HexTemplateROMFile = romhex;
        }
        public ReceiveDataTransform(string prghex, string romhex, string directoryName)
        {
            HexDirectoryName = directoryName;
            HexTemplatePRGFile = prghex;
            HexTemplateROMFile = romhex;
        }
        //public ReceiveDataTransform()
        //{
        //}
        public ReceiveDataTransform(string receive)
        {
            string[] strArr = receive.Split('\n');
            foreach (string str in strArr)
            {
                if (str.Contains(Define_OneWire_SystemData_Str))
                {
                    OneWire_SystemData_Str = str;
                }
                else if (str.Contains(Define_OneWire_EEPROM_Str))
                {
                    OneWire_EEPROM_Str = str;
                }
            }
        }
        public void setOneWire_SystemData(byte[] data)
        {
            OneWire_SystemData = data.Clone() as byte[];
        }
        public void setOneWire_EEPROM(byte[] data)
        {
            OneWire_EEPROM = data.Clone() as byte[];
        }
        public bool Transforming()
        {
            bool readyForBurning = false;
            bool burning = false;


            getModifyData();
            BarCodeID = MassUtilityClass.ByteArrayToString(BarCode1_Data) + MassUtilityClass.ByteArrayToString(BarCode2_Data);
            //BarCodeID = Regex.Replace(BarCodeID, @"[\W]+", "");  //移除所有特殊字元
            BarCodeID = Regex.Replace(BarCodeID, @"[^a-zA-Z_0-9]", "");  //移除所有特殊字元
            //TransforHexFile = "_" + BarCodeID.Replace('@', '_') + "_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".hex";
            TransforHexFile = "_" + BarCodeID + "_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".hex";

            using (StreamWriter sw = new StreamWriter(@".\Log\Org_DataLog_" + DateTime.Now.ToString("yyyyMMdd_HHmmss_") +TransforHexFile+ ".txt"))
            {
                sw.WriteLine("[OneWire_SystemData]");
                sw.WriteLine(MassUtilityClass.ByteArrayToHexString(OneWire_SystemData, true));
                sw.WriteLine("[OneWire_EEPROM]");
                sw.WriteLine(MassUtilityClass.ByteArrayToHexString(OneWire_EEPROM, true));
                sw.Close();
            }

            bool flag1;
            HexFileDocument hexFD;
            try
            {
                hexFD = new HexFileDocument();
                //flag1 = hexFD.openHexFile(Path.Combine(HexTemplatePath, HexTemplateROMFile));
                flag1 = hexFD.openHexFile(Path.Combine(HexDirectoryName, HexTemplateROMFile));
            }
            catch (Exception ex)
            {
                MessageBox.Show("HexFileDocument: " + ex.ToString(), "HexFileDocument", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return false;
            }

            if (flag1)
            {
                hexFD.setHexData((UInt16)(0x1000 + Cal_Offset), Cal_Data);
                hexFD.setHexData((UInt16)(0x1000 + MaSN_Offset), MaSN_Data);
                hexFD.setHexData((UInt16)(0x1000 + BarCode1_Offset), BarCode1_Data);
                hexFD.setHexData((UInt16)(0x1000 + BarCode2_Offset), BarCode2_Data);
                try
                {
                    hexFD.SaveHexFile(Path.Combine(HexTransformPath, TransforHexFile));
                    readyForBurning = true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("SaveHexFile: " + ex.ToString(), "SaveHexFile", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    readyForBurning = false;
                }
                if (!readyForBurning)
                {
                    return false;
                }
                
                burning = ProgramingHEX(BurningType.Unlock, Path.Combine(HexTemplatePath, HexTemplateUnlockFile));
                if (!burning)
                {
                    MessageBox.Show("Failure." + Environment.NewLine +
                        "Programing Unlock HEX File :" + Path.Combine(HexTemplatePath, HexTemplateUnlockFile) + Environment.NewLine +
                        "Please Check Connection and ReTry again.", "Programing Unlock HEX File", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    burning = ProgramingHEX(BurningType.Unlock, Path.Combine(HexTemplatePath, HexTemplateUnlockFile));
                    if (!burning) { MessageBox.Show("Failure.", "Programing Unlock HEX File", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; }
                }
                burning = ProgramingHEX(BurningType.ROM, Path.Combine(HexTransformPath, TransforHexFile));
                if (!burning)
                {
                    MessageBox.Show("Failure." + Environment.NewLine +
                        "Programing ROM HEX File :" + Path.Combine(HexTransformPath, TransforHexFile) + Environment.NewLine +
                        "Please Check Connection and ReTry again.", "Programing ROM HEX File", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    burning = ProgramingHEX(BurningType.ROM, Path.Combine(HexTransformPath, TransforHexFile));
                    if (!burning) { MessageBox.Show("Failure.", "Programing ROM HEX File", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; }
                }
                //burning = ProgramingHEX(BurningType.Prg, Path.Combine(HexTemplatePath, HexTemplatePRGFile));
                burning = ProgramingHEX(BurningType.Prg, Path.Combine(HexDirectoryName, HexTemplatePRGFile));
                if (!burning)
                {
                    MessageBox.Show("Failure." + Environment.NewLine +
                        //"Programing PROGRAM HEX File :" + Path.Combine(HexTemplatePath, HexTemplatePRGFile) + Environment.NewLine +
                        "Programing PROGRAM HEX File :" + Path.Combine(HexDirectoryName, HexTemplatePRGFile) + Environment.NewLine +
                        "Please Check Connection and ReTry again.", "Programing PROGRAM HEX File", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    //burning = ProgramingHEX(BurningType.Prg, Path.Combine(HexTemplatePath, HexTemplatePRGFile));
                    burning = ProgramingHEX(BurningType.Prg, Path.Combine(HexDirectoryName, HexTemplatePRGFile));
                    if (!burning) { MessageBox.Show("Failure.", "Programing PROGRAM HEX File", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; }
                }
                //burning = ProgramingHEX(BurningType.Lock, Path.Combine(HexTemplatePath, HexTemplateLockFile));
                //if (!burning)
                //{
                //    MessageBox.Show("Failure." + Environment.NewLine +
                //        "Programing Lock HEX File :" + Path.Combine(HexTemplatePath, HexTemplateLockFile) + Environment.NewLine +
                //        "Please Check Connection and ReTry again.", "Programing Lock HEX File", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                //    //burning = ProgramingHEX(BurningType.Lock, Path.Combine(HexTemplatePath, HexTemplateLockFile));
                //    if (!burning) { MessageBox.Show("Failure.", "Programing Lock HEX File", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; }
                //}

                return true;
            }

            return false;
        }
        private void getModifyData()
        {
            try
            {

                Array.Copy(OneWire_EEPROM, Cal_Offset, Cal_Data, 0, Cal_Data.Length);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Array.Copy1: " + OneWire_EEPROM.Length + ", " + Cal_Offset + ", " + Cal_Data.Length + Environment.NewLine
                    + ex.ToString(), "Array.Copy 1", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            try
            {

                Array.Copy(OneWire_EEPROM, MaSN_Offset, MaSN_Data, 0, MaSN_Data.Length);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Array.Copy2: " + OneWire_EEPROM.Length + ", " + MaSN_Offset + ", " + MaSN_Data.Length + Environment.NewLine
                    + ex.ToString(), "Array.Copy 2", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            //(MANUFACTURE_DATE_YEAR - 1980) * 512 + MANUFACTURE_DATE_MONTH * 32 + MANUFACTURE_DATE_DAY  // 2 bytes
            UInt16 MANUFACTURE_DATE = (UInt16)((DateTime.Now.Year - 1980) * 512 + DateTime.Now.Month * 32 + DateTime.Now.Day);
            byte[] date = BitConverter.GetBytes(MANUFACTURE_DATE);
            MaSN_Data[0] = date[1];
            MaSN_Data[1] = date[0];

            try
            {

                Array.Copy(OneWire_EEPROM, BarCode1_Offset, BarCode1_Data, 0, BarCode1_Data.Length);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Array.Copy3: " + OneWire_EEPROM.Length + ", " + BarCode1_Offset + ", " + BarCode1_Data.Length + Environment.NewLine
                    + ex.ToString(), "Array.Copy 3", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            try
            {

                Array.Copy(OneWire_EEPROM, BarCode2_Offset, BarCode2_Data, 0, BarCode2_Data.Length);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Array.Copy4: " + OneWire_EEPROM.Length + ", " + BarCode2_Offset + ", " + BarCode2_Data.Length + Environment.NewLine
                    + ex.ToString(), "Array.Copy 4", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
        }
        public enum BurningType
        {
            Prg,
            ROM,
            Lock,
            Unlock
        }
        public bool ProgramingHEX(BurningType type, string fileName)
        {
            Process ProgrammingPRG = new Process();
            // 執行路徑及檔名 
            //ProgrammingPRG.StartInfo.FileName = @"C:\Program Files\STMicroelectronics\st_toolset\stvp\STVP_CmdLine.exe";
            ProgrammingPRG.StartInfo.FileName = Path.Combine(ProgrammingPath, ProgrammingFile);
            // 額外的參數；這邊給的是網址
            switch (type)
            {
                case BurningType.Prg:
                    ProgrammingPRG.StartInfo.Arguments = ProgrammingArgumentsPRG + fileName;
                    break;
                case BurningType.ROM:
                    ProgrammingPRG.StartInfo.Arguments = ProgrammingArgumentsROM + fileName;
                    break;
                case BurningType.Lock:
                    ProgrammingPRG.StartInfo.Arguments = ProgrammingArgumentsLOCK + fileName;
                    break;
                case BurningType.Unlock:
                    ProgrammingPRG.StartInfo.Arguments = ProgrammingArgumentsUNLOCK + fileName;
                    break;
            }

            //ProgrammingPRG.Start();
            ////////////////////////////////////////////////////////////////////////////////////////
            ProgrammingPRG.StartInfo.UseShellExecute = false;  //啟動標準輸出為True
            ProgrammingPRG.StartInfo.RedirectStandardOutput = true;
            //ProgrammingPRG.StartInfo.WorkingDirectory = Application.StartupPath;
            ProgrammingPRG.Start();
            //讀取外部程式執行時產生的標準輸出內容   
            string TskOutput = ProgrammingPRG.StandardOutput.ReadToEnd();
            ProgrammingPRG.WaitForExit();
            ProgrammingPRG.Close();
            bool success = isProgrammingSuccess(TskOutput);
            using (StreamWriter sw = new StreamWriter(@".\Log\_BurningLog_" + type.ToString() + "_" + DateTime.Now.ToString("yyyyMMdd_HHmmss_") + TransforHexFile + ".txt"))
            {
                sw.WriteLine(TskOutput);
                sw.Close();
            }
            return success;
            //MessageBox.Show(success.ToString());
        }
        private bool isProgrammingSuccess(string TaskOutput)
        {
            string[] LineArr = TaskOutput.Split('\n');
            if (LineArr.Length > 50)
            {
                //fail
                return false;
            }
            List<string> checkLines = new List<string>();
            foreach (string str in LineArr)
            {
                string str1 = str.Replace('\r', ' ').Trim();
                if (str1.StartsWith("<<<") && str1.Contains("succeeds"))
                {
                    checkLines.Add(str1);
                }
            }

            if (checkLines.Count >= 3)
            {
                if (checkLines[1].Contains("OPTION BYTE") && (checkLines.Count == 3))
                {
                    checkLines.Clear();
                    return true;
                }
                else if (checkLines[0].Contains("PROGRAM MEMORY") && (checkLines.Count == 4))
                {
                    checkLines.Clear();
                    return true;
                }
                else if (checkLines[0].Contains("DATA MEMORY") && (checkLines.Count == 4))
                {
                    checkLines.Clear();
                    return true;
                }
            }
            checkLines.Clear();
            return false;
        }

    }//class ReceiveDataTransform
}
